package com.itheima.stock.service.impl;

import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.stock.common.domain.*;
import com.itheima.stock.mapper.*;

import com.itheima.stock.pojo.StockBusiness;

import com.itheima.stock.service.StockService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.vo.req.PageResult;
import com.itheima.stock.vo.res.R;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import org.checkerframework.checker.units.qual.C;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.unit.DataUnit;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 定义股票服务接口实现
 */
@Service("stockService")
@Slf4j
public class StockServiceImpl implements StockService {

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;
    @Autowired
    private StockOuterMarketIndexInfoMapper stockOuterMarketIndexInfoMapper;


    /**
     * 查询所有主营业务信息
     *
     * @return
     */
    @Override
    public List<StockBusiness> findAll() {
        return stockBusinessMapper.getAll();
    }

    /**
     * 获取最新的国内大盘参数
     *
     * @return
     */
    @Override
    public R<List<InnerMarketDomain>> getInnerMarketInfos() {
        //1.获取最近最新的一次股票交易时间
        Date curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //先用一个假数据测试，后期删除
       // curDateTime = DateTime.parse("2021-12-28 09:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.根据指定时间点和对应的大盘id查询对应的信息
        List<InnerMarketDomain> infos = stockMarketIndexInfoMapper.findMarketInfoByTimeAndCodes(curDateTime, stockInfoConfig.getInner());
        //将数据返回给前端
        return R.ok(infos);
    }

    /**
     * 查询最近最新的板块信息
     * @return
     */
    @Override
    public R<List<StockBlockDomain>> getstockBlockInfo() {
        //1.获取最近最新的一次股票交易时间
        Date curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //先用一个假数据测试，后期删除
       // curDateTime = DateTime.parse("2022-01-14 16:57:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.根据时间查询对应的大盘数据信息
        List<StockBlockDomain> infos =  stockBlockRtInfoMapper.findBlockInfoByTimeLimit(curDateTime);
        //3.响应
        return R.ok(infos);

    }


    /**
     * 统计A股最新的交易数据，并按照涨幅去前10
     * @return
     */
    @Override
    public R<List<StockUpdownDomain>> getStockInfoByIncrease() {
        //1.获取当前最新的股票交易时间点
        Date curDate=DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //由于暂时没有当前时间的数据，则暂时有伪数据
       // curDate= DateTime.parse("2022-03-21 14:33:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.调用mapper根据时间点获取股票
        List<StockUpdownDomain> infos=stockRtInfoMapper.getStockInfoByIncrease(curDate);
        //3.返回数据
        return R.ok(infos);
    }

    /**
     * 分页查询股票数据
     * @param page 当前页
     * @param pageSize 每页大小
     * @return
     */
    @Override
    public R<PageResult<StockUpdownDomain>> getStockByPage(Integer page, Integer pageSize) {
        //1.设置分页参数---》底层自动为当前值执行查询的sql添加liit语句，实现分页
        PageHelper.startPage(page,pageSize);
        //2.查询
        List<StockUpdownDomain> infos=stockRtInfoMapper.getStockAll();
        //3.构建PageHelpher分页详情对象
        PageInfo<StockUpdownDomain> pageInfo =new PageInfo<>(infos);
        //4.转化为自定义分页大户局--》目的：精简数据
        PageResult<StockUpdownDomain> pageResult = new PageResult<>(pageInfo);
        //返回数据
        return R.ok(pageResult);

    }

    /**
     * 统计T日每分钟股票的涨停跌停数据
     * @return
     */
    @Override
    public R<Map> getStockUpdownCount() {
        //1.获取当前最近有效时间点
        DateTime netDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //获取截止日期时间点
        Date endTime = netDateTime.toDate();
        //获取endTime对应的开盘时间
        Date startTime = DateTimeUtil.getOpenDate(netDateTime).toDate();
//        //TODO MOCKDATA伪数据
//        endTime=DateTime.parse("2022-01-06 14:25:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//        startTime=DateTime.parse("2022-01-06 09:25:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//

        //2. 根据时间范围获取对应的涨停跌停数  约定：flag--->1：涨停     0：跌停
        //2.1 获取涨停猪
        List<Map> upList= stockRtInfoMapper.getStockUpdownCount(startTime,endTime,1);
        List<Map> downList= stockRtInfoMapper.getStockUpdownCount(startTime,endTime,0);

        //3. 组装数据响应前端
        Map<String,List> mapInfo=new HashMap<>();
        mapInfo.put("upList",upList);
        mapInfo.put("downList",downList);

        //返回
        return R.ok(mapInfo);
    }

    /**
     * 股票数据导出到excel中
     * @param response  响应体对象
     * @param page  当前页
     * @param pageSize  每页大小
     */
    @Override
    public void exportStockInf4Excel(HttpServletResponse response, Integer page, Integer pageSize) {
        try {
            //1.设置响应数据的类型:excel
            response.setContentType("application/vnd.ms-excel");
            //2.设置响应数据的编码格式
            response.setCharacterEncoding("utf-8");
            //3.设置默认的文件名称
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("stockRt", "UTF-8");
            //设置默认文件名称
            response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xlsx");
            //4.获取分页数据
            PageHelper.startPage(page,pageSize);
            List<StockUpdownDomain> infos = stockRtInfoMapper.getStockAll();
            //5.给前端 响应数据
            EasyExcel.write(response.getOutputStream(),StockUpdownDomain.class).sheet("股票数据")
                    .doWrite(infos);
        } catch (IOException e) {
            log.info("导出数据异常:{}",e.getMessage());
        }
    }

    /**
     *
     * @return
     */
    @Override
    public R<Map> getStockUpDownScopeNum() {
        //1.获取最新的股票交易时间点
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
//        //todo mock data
//        curDate=DateTime.parse("2022-01-06 09:55:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//        //\todo mock data
        //2.根据指定时间查询涨幅区间数量
        List<Map> rangeInfo = stockRtInfoMapper.getLastDate4Stock(curDate);
        //2.1 补充：补齐残缺范围没有数据的问题  2.将title标题合理排序在前端展示
        //方式2:使用lambda表达式实现stream
        List<Map> maps = stockInfoConfig.getUpDownRange().stream().map(title -> {
            Optional<Map> optional = rangeInfo.stream().filter(map -> title.equals(map.get("title"))).findFirst();
            Map map = null;
            if (optional.isPresent()) {
                map = optional.get();
            } else {
                map = new HashMap();
                map.put("title", title);
                map.put("count", 0);
            }
            return map;

        }).collect(Collectors.toList());

        //方式1：
//        ArrayList<Map> maps=new ArrayList<>();
//        for (String title : stockInfoConfig.getUpDownRange()) {
//            Map tmp=null;
//            for (Map map : rangeInfo) {
//                if(map.get("title".equals(title)){
//                    tmp=map;
//                    break;
//                }
//            }
//            if (tmp==null) {
//                tmp=new HashMap();
//                tmp.put("title",title);
//                tmp.put("count",0);
//            }
//            maps.add(tmp);
//        }


        //3.组装数据
        Map data=new HashMap();
        String curStrDate=new DateTime(curDate).toString(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm"));
        data.put("time",curStrDate);
//        data.put("infos",rangeInfo);
        data.put("infos",maps);
        //4.返回数据
        return R.ok(data);
    }

    /**
     * 通过T日和T-1日大盘成交量对比数据
     * @return
     */
    @Override
    public R<Map<String, List>> getStockCompareTradeVol() {
        //1.1获取T日最新的一次股票交易时间点
        DateTime tDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date tEndTime = tDateTime.toDate();
        //1.2获取T日开盘时间
        Date tStartTime = DateTimeUtil.getOpenDate(tDateTime).toDate();
        //2.1 获取T-1日对应的截止时间，保证与T日时间线对齐
        //获取上一日时间
        DateTime preTDateTime = DateTimeUtil.getPreviousTradingDay(tDateTime);
        Date preTEndTime = preTDateTime.toDate();
        //2.2 获取上一个交易日的开盘时间
        Date preTStartTime = DateTimeUtil.getOpenDate(preTDateTime).toDate();

//        //TODO MOCK DATA
//        tEndTime=DateTime.parse("2022-01-03 14:40:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//        tStartTime=DateTime.parse("2022-01-03 09:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//
//        preTEndTime=DateTime.parse("2022-01-02 14:40:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//        preTStartTime=DateTime.parse("2022-01-02 09:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//        //\TODO MOCK DATA

        //3.调用mapper接口获取数据
        //3.1获取T日成交量数据
        List<Map> tData= stockMarketIndexInfoMapper.getTradeVolInfoByTime(stockInfoConfig.getInner(),tStartTime,tEndTime);
        //3.2获取T-1日的成交量数据
        List<Map> preTData= stockMarketIndexInfoMapper.getTradeVolInfoByTime(stockInfoConfig.getInner(),preTStartTime,preTEndTime);

        //4.组装数据
        Map<String,List> data=new HashMap<>();
        data.put("volList",tData);
        data.put("yesVolList",preTData);
        //5.返回响应的数据
        return R.ok(data);
    }

    /**
     * 查询股票的分时数据
     * @param stockCode
     * @return
     */
    @Override
    public R<List<Stock4MinuteDomain>> getStockScreenTimeSharing(String stockCode) {
        //1.获取最新股票交易时间点
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //2.截止日期
        Date endTime = curDateTime.toDate();
        //3.开盘时间
        Date startTime = DateTimeUtil.getOpenDate(curDateTime).toDate();
//        //todo mock data
//        endTime=DateTime.parse("2021-12-30 14:40:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//        startTime=DateTime.parse("2021-12-30 09:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//        //\todo mock data
        //4.查询数据
        List<Stock4MinuteDomain> data= stockRtInfoMapper.getStockScreenTimeSharing(stockCode,startTime,endTime);
        //返回数据
        return R.ok(data);
    }

    /**
     * 查询股票日K信息
     * @param stockCode
     * @return
     */
    @Override
    public R<List<Stock4EvrDayDomain>> getStockScreenDayKLine(String stockCode) {
        //1.获取最新股票交易时间点
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endDate = endDateTime.toDate();
        //向后推n天
        DateTime startDateTime = DateTimeUtil.getOpenDate(endDateTime.minusDays(10));
        Date startDate = startDateTime.toDate();
//        //todo mock data
//        endDate = DateTime.parse("2022-01-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//        startDate = DateTime.parse("2022-01-01 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//        //\todo mock data
        //2.查询股票日K线信息
        List<Stock4EvrDayDomain> infos = stockRtInfoMapper.getStockScreenDayKLine(stockCode, startDate, endDate);
        return R.ok(infos);
    }

    /**
     * 获取个股最新分时行情数据，包含开盘价、前收盘价、最新价、最高价、最低价、成交金额和成交量信息
     * @param stockCode 股票编码
     * @return
     */
    @Override
    public R<Map> getStockSecondDetail(String stockCode) {
        //获取当前最近的有效时间
        String recentAvalDate = DateTimeUtil.getLastDateString4Stock(DateTime.now());
        //分时查询
        Map infos= this.stockRtInfoMapper.getStockSecondDetail(stockCode,recentAvalDate);
        if (CollectionUtils.isEmpty(infos)) {
            return R.error("暂无数据");
        }
        return R.ok(infos);

    }

    /**
     * 外盘指数
     * 外盘指数行情查询，根据时间取前4
     * @return
     */
    @Override
    public R<List<Map>> getExternalIndex() {
        //获取外盘ids
        List<String> outerIds = stockInfoConfig.getOuter();
        //TODO MOCKDATE 外盘数据 时间点不一致
        Date timePoint=DateTime.parse("2021-12-01 10:57:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        List<Map> maps=this.stockOuterMarketIndexInfoMapper.getExternalIndex(outerIds,timePoint);
        if (CollectionUtils.isEmpty(maps)) {
            return R.error("暂无数据");
        }
        return R.ok(maps);

    }

    /**
     * 格局输入的个股代码，进行模糊查询，返回证券代码和证券名称
     * @param searchStr 个股代码模糊搜索
     * @return
     */
    @Override
    public R<List<Map>> searchStock(String searchStr) {
        if(StringUtils.isEmpty(searchStr)){
            return R.error("暂无数据");
        }
        List<Map> maps=stockBusinessMapper.searchStockLike(searchStr);

        if(CollectionUtils.isEmpty(maps)){
            return R.error("暂无数据");
        }

        return R.ok(maps);
    }

    /**
     * 根据股票编号获取所对应的公司详情信息
     * @param stockCode
     * @return
     */
    @Override
    public R<Map> getStockDescribe(String stockCode) {
        //获取股票编码
        Map infos =stockBusinessMapper.getBussinessInfoByCode(stockCode);
        if(CollectionUtils.isEmpty(infos)){
            return R.error("暂无数据");
        }
        return R.ok(infos);
    }

    /**
     * 单个个股周k线数据：包含股票ID，最高价 最低价 开盘价 收盘价 均价
     * 具体：最高和最低是一周内的
     *      开盘与收盘分别对应周1的看盘价格和周五的收盘价格
     *      均价就是一周的平均价格
     *      日期：一周内的最大日期，一般是周五
     * @param stockCode 股票编码
     * @return
     */
    @Override
    public R<List<Map>> getWeekLinData(String stockCode) {
        List<Map> infos= stockRtInfoMapper.getWeekLinData(stockCode);
        if(CollectionUtils.isEmpty(infos)){
            return R.error("暂无数据");
        }
        return R.ok(infos);
    }

    /**
     * 获取个股实时交易流水信息，按照时间降序排序，取前10
     * 单个个股秒级行情数据查询，查询当前分钟内的秒级数据（我们当前一分钟为单位获取数据）
     * @param code 股票编码
     * @return
     */
    @Override
    public R<List<Map>> getStockScreenSecond(String code) {
        //获取之后2分钟的时间
        String preDateTime= DateTime.now().minusMinutes(2).toString(DateTimeFormat.forPattern("yyyyMMddHHmm"));
        //获取当前分钟下的股票数据
        List<Map> infos =stockRtInfoMapper.getStockScreenSecond(code);
        if(CollectionUtils.isEmpty(infos)){
            return R.error("暂无数据");
        }
        return R.ok(infos);
    }
}
